#include <iostream>
#include <fstream>
#include <string>
#include <thread>
#include <mutex>

using namespace std;

string currentTime()
{
    time_t timep;
    struct tm *p;
    time(&timep);          // 获取从1970至今过了多少秒，存入time_t类型的timep
    p = localtime(&timep); // 用localtime将秒数转化为struct tm结构体
    string str = "";
    str += to_string(1900 + p->tm_year) + "-" + to_string(1 + p->tm_mon) + "-" + to_string(p->tm_mday) + "-" + to_string(p->tm_hour) + "-" + to_string(p->tm_min) + "-" + to_string(p->tm_sec);
    return str;
}

enum class log_level
{
    debug,
    info,
    warn,
    error
};

enum class log_target
{
    terminal,
    file,
    all
};

class log
{
private:
    void write(string msg, log_level l1);

public:
    log();
    log(log_target l1, log_level l2, string p = "");
    void debug(string msg) { write(msg, log_level::debug); }
    void info(string msg) { write(msg, log_level::info); }
    void warn(string msg) { write(msg, log_level::warn); }
    void error(string msg) { write(msg, log_level::error); }
    ~log();

private:
    ofstream outfile;
    log_level ll;
    log_target lt;
    string path;
};

log::log()
{
    ll = log_level::error;
    lt = log_target::all;
    path = currentTime() + ".log";
    string m = "[Welcome]     " + currentTime() + " : " + "=== Start logging ===\n";
    outfile.open(path, ios::app);
    if (outfile.is_open())
        outfile << m;
    cout << m;
}

log::log(log_target l1, log_level l2, string p)
{
    lt = l1;
    ll = l2;
    path = p;
    string m = "[Welcome]     " + currentTime() + " : " + "=== Start logging ===\n";
    if (lt != log_target::terminal)
    {
        if (p.empty())
            path = currentTime() + ".log";
        outfile.open(path, ios::app);
        if (outfile.is_open())
            outfile << m;
    }
    if (lt != log_target::file)
    {
        cout << m;
    }
}

void log::write(string msg, log_level l1)
{
    string tmp;
    if (l1 == log_level::debug)
        tmp = "[DEBUG]       ";
    else if (l1 == log_level::info)
        tmp = "[INFO]        ";
    else if (l1 == log_level::warn)
        tmp = "[WARN]        ";
    else if (l1 == log_level::error)
        tmp = "[ERROR]       ";
    else
    {
        return;
    }
    tmp += currentTime() + " : " + msg + "\n";
    if (lt != log_target::terminal)
        outfile << tmp;
    if (lt != log_target::file)
        cout << tmp;
}

log::~log()
{
    if (outfile.is_open())
        outfile.close();
}

int i = 0;

mutex mtx;

void write_in_log(log *l)
{
    lock_guard<mutex> lock(mtx);
    if (i % 4 == 0)
        l->debug("-debug-" + to_string(i));
    else if (i % 4 == 1)
        l->info("-info-" + to_string(i));
    else if (i % 4 == 2)
        l->warn("-warn-" + to_string(i));
    else if (i % 4 == 3)
        l->error("-error-" + to_string(i));
    i++;

}

int main()
{
    log l(log_target::all, log_level::error);
    for(int j=0;j<8;j++)
    {
        thread t(write_in_log,&l);
        t.join();
    }
    return 0;
}